//
// transreg.cpp
// libprotea
// Tools Library for the Protea Project / Business Transaction Registration
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// Please send correspondence to:
// 
// theproteaproject@gmail.com
//

#include "../defines.h"
#include "../OSDep/shlib.h"
#include "transreg.h"

// Define hash table size
const int HASH_SIZE = 100;

// Make the hash function a macro (for speed)
#define hashfunc(x) (x % HASH_SIZE);


XCTransRegServer::XCTransRegServer() {
	Hash = new XCTransRegTransaction*[ HASH_SIZE ];
	for (int i=0; i<HASH_SIZE; i++)
		Hash[i] = NULL;

	Libraries = NULL;
};


XCTransRegServer::~XCTransRegServer() {
	// Destroy transaction list
	for (int i=0; i<HASH_SIZE; i++) {
		// For each hash bucket, follow the linked list chain
		XCTransRegTransaction* temp = Hash[i];
		while (temp) {
			XCTransRegTransaction* temp2 = temp;
			temp = temp->next;
			delete temp2;
		};
	};

	// Destroy the hash structure
	delete [] Hash;

	// Destroy library list - close open libraries
	XCTransRegLibrary* temp = Libraries;
	while (temp) {
		XCTransRegLibrary* deleteme = temp;
		assert( temp->module );
		temp->module->Close();
		temp = temp->next;
		delete deleteme;
	};
};


bool XCTransRegServer::RegisterLibrary( const char* name, XCSharedLibrary* library ) {
	typedef bool (*reg_func)( XCTransRegServer* );

	assert( library );

	// Were we given a valid module??
	if (library) {
		// Verify that this module is in fact a Protea Project extension, by checking for
		// 'XCTransactionCode' symbol
		try {
			reg_func registration = (reg_func)library->GetLibAddress( "XCTransactionCode" );
			// If it exists, grab the module name, and ask whether we should register
			if (registration( this )) {
				XCTransRegLibrary* temp = new XCTransRegLibrary();
				temp->description = strdup( name );
				temp->next = Libraries;
				temp->module = library;
				Libraries = temp;

//				printf( "Library %s registered\n" );
				return true;
			} else {
				printf( "Library %s chose not to register!\n", name );
			};
		} catch( ... ) {
			printf( "Not an extension library!\n" );
		};
	};
	return false;
};

bool XCTransRegServer::RegisterTransaction( long trans_number, trans_func_type trans_code ) {
	XCTransRegTransaction* temp = new XCTransRegTransaction();

	// Hash the transaction name
	long hash_result = hashfunc( trans_number );

	// Insert into the hash table
	temp->next = Hash[ hash_result ];
	Hash[ hash_result ] = temp;

	// Set the transaction information
	temp->trans_number = trans_number;
	temp->transaction_code = trans_code;
	temp->calls = 0;

	// Increase the transaction count
	transaction_count++;

	return true;
};



XCTransRegTransaction* XCTransRegServer::FindTransaction( long trans_number ) {
	long hash_result = hashfunc( trans_number );

	XCTransRegTransaction* temp = Hash[ hash_result ];
	while (temp && temp->trans_number != trans_number)
		temp = temp->next;

	return temp;
};



void XCTransRegServer::OutputHashTable() {
	for (int i=0; i<HASH_SIZE; i++) {
		int count = 0;

		printf( "Level %3d: ", i );

		XCTransRegTransaction* temp = Hash[i];
		while (temp) {
/*
			if (count)
				printf( ",%d", temp->trans_number );
			else
				printf( "%d", temp->trans_number );
*/
			printf( "*" );
			count++;
			temp = temp->next;
		};

//		printf( "\n\tTotal: %d\n", count );
		printf( "\n" );
	};
};
